package com.yihr.aop;


import com.yihr.ApiResponse;
import com.yihr.aop.security.SecurityInterface;
import com.yihr.bean.TokenRes;
import com.yihr.util.JwtUtil;
import com.yihr.util.StringUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@Aspect
@Component
public class SecurityAspect {

    public static final Logger LOGGER = LoggerFactory.getLogger(SecurityAspect.class);

    private static final String JWT_TAG = "jwt";

    //Controller层切点，也就是上面那个注解的路径
    @Pointcut("@annotation(com.yihr.aop.security.SecurityInterface)")
    public void pointcutSecurity() {
    }


    private String getRole(ProceedingJoinPoint point) {
        MethodSignature ms = (MethodSignature) point.getSignature();
        return ms.getMethod().getAnnotation(SecurityInterface.class).role();
    }

    private String getJwt() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String jwt = request.getHeader(JWT_TAG);

        if (StringUtil.isEmpty(jwt)) {
            Cookie[] cookies = request.getCookies();
            if (null != cookies && cookies.length > 0) {
                for (int i = 0; i < cookies.length; i++) {
                    if (JWT_TAG.equals(cookies[i].getName())) {
                        jwt = cookies[i].getValue();
                        break;
                    }
                }
            }
        }

        return jwt;
    }

//    @Around("pointcutSecurity()")
    @Around("@annotation(com.yihr.aop.security.SecurityInterface)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        LOGGER.info("@Around start ...");
        System.err.println("=================round=================");

        String jwt = getJwt();
        if (StringUtil.isEmpty(jwt)) {
            throw new RuntimeException("JWT 缺失");
        }

        TokenRes tokenRes = JwtUtil.decodeToken(jwt);
        if (tokenRes.isOutTime()) {
            throw new RuntimeException("JWT 已过期");
        } else if (!tokenRes.isNbf()) {
            throw new RuntimeException("JWT 未生效");
        }

        Map<String, Object> body = tokenRes.getMapBody();
        long id = Long.parseLong(body.getOrDefault("uid", 0L).toString());

        Object[] args = point.getArgs();
        if (id != (long)args[0]) {
            throw new RuntimeException("ID 不一致");
        }

        String role = getRole(point);
        if (!"user".equals(role)) {
            String userRole = body.getOrDefault("role", "user").toString();
            if (!userRole.contains(role)) {
                throw new RuntimeException("需要角色：" + role);
            }
        }

        ApiResponse response = (ApiResponse) point.proceed(args);
        if (!tokenRes.isExp()) {
            response.jwt(JwtUtil.freshJwtDT(body));
        }

        // 在这块可以记日志。
        return response;
    }


}
